package org.example.infrastructure.adapter.repository;


import lombok.extern.slf4j.Slf4j;
import org.example.domain.order.adapter.repository.IOrderRepository;
import org.example.domain.order.model.entity.DelayCancelOrderEntity;
import org.example.domain.order.model.entity.OrderEntity;
import org.example.domain.shop.model.entity.ProductEntity;
import org.example.domain.transaction.model.entity.RefundCallBackEntity;
import org.example.infrastructure.dao.IDelayCancelOrderTopicRetryDao;
import org.example.infrastructure.dao.IOrderDao;
import org.example.infrastructure.dao.IProductDao;
import org.example.infrastructure.dao.IProductInventoryDao;
import org.example.infrastructure.dao.po.DelayCancelOrderTopicRetryPO;
import org.example.infrastructure.dao.po.OrderPO;
import org.example.infrastructure.dao.po.ProductPO;
import org.example.infrastructure.redis.IRedisService;
import org.example.types.enums.ResponseCode;
import org.example.types.exception.AppException;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static org.example.types.common.RedisConstants.PRODUCT_INFO_PREFIX;
import static org.example.types.common.RedisConstants.PRODUCT_INFO_TTL;

/**
 * @author yinghuashen
 * @version 1.0
 * @description
 * @date 2025/3/10 09:57
 */

@Slf4j
@Repository
public class OrderRepository implements IOrderRepository {

    @Resource
    private IRedisService redisService;

    @Resource
    private IProductDao productDao;

    @Resource
    private IOrderDao orderDao;

    @Resource
    private IProductInventoryDao productInventoryDao;

    @Resource
    private IDelayCancelOrderTopicRetryDao delayCancelOrderTopicRetryDao;

    @Override
    public ProductEntity getProductById(String productId) {
        // OrderRepository中的getProductById只需要:
        // 商品id，商品名称，商品原价和优惠价格

        // 逻辑过期
        String info_key = PRODUCT_INFO_PREFIX + productId;
        ProductPO productPO = redisService.getCacheObjectWithLogicalExpire(info_key, productId,
                ProductPO.class, productDao::getProductById, PRODUCT_INFO_TTL, TimeUnit.MINUTES);

        if (productPO == null) {
            return null;
        }

        return ProductEntity.builder()
                .productId(productPO.getProductId())
                .productName(productPO.getProductName())
                .originalPrice(productPO.getOriginalPrice())
                .discountPrice(productPO.getOriginalPrice())
                .build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveOrder(OrderEntity orderEntity) {
        OrderPO orderPO = OrderPO.builder().
                orderId(orderEntity.getOrderId()).
                productId(orderEntity.getProductId()).
                userId(orderEntity.getUserId()).
                productName(orderEntity.getProductName()).
                productAmount(orderEntity.getProductAmount()).
                originalPrice(orderEntity.getOriginalPrice()).
                payPrice(orderEntity.getPayPrice()).
                status(orderEntity.getStatus()).
                build();
        int res = 0;
        try {
            res = orderDao.saveOrder(orderPO);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return res > 0;
    }

    @Override
    public boolean checkOrderExists(String orderId) {
        // 根据订单ID查询订单是否存在
        OrderPO orderPO = orderDao.getOrderById(orderId);
        return orderPO != null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveDelayCancelOrderMsg(DelayCancelOrderEntity delayCancelOrderEntity) {
        DelayCancelOrderTopicRetryPO delayCancelOrderEntityPO = DelayCancelOrderTopicRetryPO.builder()
                .orderId(delayCancelOrderEntity.getOrderId()).userId(delayCancelOrderEntity.getUserId()).build();
        try {
            delayCancelOrderTopicRetryDao.insert(delayCancelOrderEntityPO);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public int getOrderStatusById(String orderId) {
        OrderPO orderPO = orderDao.getOrderById(orderId);
        if (orderPO == null) {
            return -1;
        }
        return orderPO.getStatus();
    }

    @Override
    public BigDecimal getOrderPayPriceByOrderId(String orderId) {
        return orderDao.getOrderPayPriceByOrderId(orderId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean closeDelayedOrder(String orderId) {
        OrderPO orderPO = OrderPO.builder().
                orderId(orderId).status(OrderEntity.OrderStatus.CANCELLED.getCode()).build();
        int res = orderDao.updateOrderStatus(orderPO);
        return res > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean succeedPayOrder(String orderId) {

        OrderPO orderPO = orderDao.getOrderById(orderId);
        if (orderPO == null || orderPO.getStatus() != OrderEntity.OrderStatus.PENDING_PAYMENT.getCode()) {
            log.error("succeedPayOrder 订单不存在或订单状态不为待支付：orderId = {}", orderId);
            return false;
        }

        // 更新订单状态为已支付
        orderPO.setStatus(OrderEntity.OrderStatus.PAID.getCode());
        if (orderDao.updateOrderStatus(orderPO) == 0) {
            log.error("succeedPayOrder 更新订单状态失败：orderId = {}", orderId);
            throw new AppException(ResponseCode.ORDER_DB_UPDATE_ERROR);
        }


        Map<String, Object> decreaseProductAvailableStockParams = new HashMap<>();
        decreaseProductAvailableStockParams.put("productId", orderPO.getProductId());
        decreaseProductAvailableStockParams.put("productAmount", orderPO.getProductAmount());
        if (productInventoryDao.decreaseProductAvailableStock(decreaseProductAvailableStockParams) == 0) {
            log.error("succeedPayOrder 减少库存失败：orderId = {}", orderId);
            throw new AppException(ResponseCode.ORDER_DB_UPDATE_ERROR);
        }

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean refundOrder(RefundCallBackEntity refundCallBackEntity) {
        OrderPO orderPO = orderDao.getOrderById(refundCallBackEntity.getOrderId());
        if (orderPO == null) {
            log.error("refundOrder 订单不存在：orderId = {}", refundCallBackEntity.getOrderId());
            return false;
        }

        int currentStatus = orderPO.getStatus();
        if (currentStatus != OrderEntity.OrderStatus.PENDING_PAYMENT.getCode() &&
                currentStatus != OrderEntity.OrderStatus.PAID.getCode()) {
            log.error("refundOrder 订单状态不正确：orderId = {}, currentStatus = {}",
                    refundCallBackEntity.getOrderId(), currentStatus);
            return false;
        }

        // 更新订单状态为已取消
        orderPO.setStatus(OrderEntity.OrderStatus.CANCELLED.getCode());
        if (orderDao.updateOrderStatus(orderPO) == 0) {
            log.error("refundOrder 更新订单状态失败：orderId = {}", refundCallBackEntity.getOrderId());
            throw new AppException(ResponseCode.ORDER_DB_UPDATE_ERROR);
        }

        // 若订单已支付，则恢复库存
        Map<String, Object> rollbackProductAvailableStockParams = new HashMap<>();
        rollbackProductAvailableStockParams.put("productId", orderPO.getProductId());
        rollbackProductAvailableStockParams.put("productAmount", orderPO.getProductAmount());
        if (currentStatus == OrderEntity.OrderStatus.PAID.getCode() &&
                productInventoryDao.rollbackProductAvailableStock(rollbackProductAvailableStockParams) == 0) {
            log.error("refundOrder 恢复库存失败：orderId = {}", refundCallBackEntity.getOrderId());
            throw new AppException(ResponseCode.ORDER_DB_UPDATE_ERROR);
        }

        return true;
    }

    @Override
    public ProductEntity getProductByIdNow(String productId) {
        String info_key = PRODUCT_INFO_PREFIX + productId;
        ProductPO productPO = redisService.getCacheObjectWithLogicalExpire(info_key, productId,
                ProductPO.class, productDao::getProductById, PRODUCT_INFO_TTL, TimeUnit.MINUTES);

        if (productPO == null) {
            productPO = productDao.getProductById(productId);
        }

        return ProductEntity.builder().
                productId(productPO.getProductId()).
                productName(productPO.getProductName()).
                originalPrice(productPO.getOriginalPrice()).
                discountPrice(productPO.getOriginalPrice()).
                build();
    }
}
